import { updateQueue } from "./Component";

/**
 * 事件绑定
 * @param {*} dom 真实DOM
 * @param {*} eventType 事件类型
 * @param {*} handler 事件处理函数
 */
export function addEvent(dom, eventType, handler) {
  const store = dom.store || (dom.store = {});
  store[eventType] = handler;

  // react17 把事件代理到react管理的根元素 root 上了，react17 以前代理到 document 上
  if (!document[eventType]) {
    document[eventType] = dispatchEvent;
  }
}

function dispatchEvent(event) {
  // 修改为需要批量更新
  updateQueue.isBatchingUpdate = true;

  let { target, type } = event;
  const eventType = `on${type}`;

  // const { store } = target;
  // const handler = store && store[eventType];
  // handler && handler(event);
  // target = target.parentNode;

  const syntheticEvent = createSyntheticEvent(event);

  // while 模拟冒泡事件
  while (target) {
    syntheticEvent.currentTarget = target;
    const { store } = target;
    const handler = store && store[eventType];
    handler && handler(syntheticEvent);
    // 在执行 handler 的过程中可以阻止冒泡
    if (syntheticEvent.isPropagationStopped) {
      break;
    }
    // 循环时候不断设置为父节点
    target = target.parentNode;
  }

  updateQueue.batchUpdate();
}

// 合成事件：可以屏蔽浏览器的差异
function createSyntheticEvent(nativeEvent) {
  const syntheticEvent = {}; // 存储原生事件上的属性拷贝到合成事件对象上
  for (const key in nativeEvent) {
    let value = nativeEvent[key];
    if (typeof value === "function") {
      value = value.bind(nativeEvent);
    }
    syntheticEvent[key] = value;
  }

  syntheticEvent.nativeEvent = nativeEvent;
  syntheticEvent.isDefaultPrevented = false;
  syntheticEvent.isPropagationStopped = false;
  syntheticEvent.preventDefault = preventDefault;
  syntheticEvent.stopPropagation = stopPropagation;

  return syntheticEvent;
}

function preventDefault() {
  this.defaultPrevented = true;
  const event = this.nativeEvent;
  if (event.preventDefault) {
    event.preventDefault();
  } else {
    //IE
    event.returnValue = false;
  }
  this.isDefaultPrevented = true;
}

function stopPropagation() {
  const event = this.nativeEvent;
  if (event.stopPropagation) {
    event.stopPropagation();
  } else {
    //IE
    event.cancelBubble = true;
  }
  this.isPropagationStopped = true;
}
